home *** CD-ROM | disk | FTP | other *** search
- unit P10Build;
-
- {$I+} { I/O checking is always on }
-
- {$DEFINE UseIntegerOP}
-
- // NOTE: Removed old and buggy code for Dyna conditional define - HV
-
- interface
-
- uses
- Parser10,
- SysUtils, Classes;
-
- procedure ParseFunction( FunctionString: string; { the unparsed string }
- Variables: TStringlist; { list of variables }
-
- { lists of available functions }
- FunctionOne, { functions with ONE argument, e.g. exp() }
- FunctionTwo: TStringList; { functions with TWO arguments, e.g. max(,) }
-
- UsePascalNumbers: boolean; { true: -> Val; false: StrToFloat }
-
- { return pointer to tree, number of performed operations and error state }
- var FirstOP : POperation;
-
- var Error : boolean);
- { error actually is superfluous as we are now using exceptions }
-
-
-
- implementation
-
-
- { helper functions }
-
- var
- CharTable:array[#0..#255] of byte;
-
- (*function RemoveBlanks(const s: string): string;
- { deletes all blanks in s }
- var
- i : integer;
- begin
- Result := s;
-
- i := pos(' ', Result);
- while i > 0 do
- begin
- delete(Result, i, 1);
- i := pos(' ', Result);
- end;
- end;*)
-
- function TryStrToFloat(const S: string; var Value: Double): boolean;
- var
- ExtValue: Extended;
- begin
- Result := TextToFloat(PChar(S), ExtValue, fvExtended);
- if Result then
- Value := ExtValue;
- end;
-
- function HackSetLength(var S: String; NewLen: Integer): integer;
- type
- PInteger = ^Integer;
- begin
- Result := Length(S);
- {$IFDEF Win32}
- PInteger(Longint(S)-4)^ := NewLen;
- {$ELSE}
- S[0] := Chr(NewLen);
- {$ENDIF}
- end;
-
- {$IFNDEF Win32}
- procedure SetLength(var S: String; NewLen: Integer);
- begin
- S[0] := Chr(NewLen);
- end;
- {$ENDIF]
-
- { case INSENSITIVE }
- procedure MakeCharTable;
- var
- I: Integer;
- begin
- for I := 0 to 255 do
- begin
- If (I > 64) and (I < 91) then
- CharTable[Char(I)]:= I + 32
- else
- CharTable[Char(I)]:= I;
- end;
- end; { MakeCharTable }
-
- function IPos(Pat, Text: PChar):Integer;
- var
- RunPat, RunText, PosPtr: PChar;
- begin
- Result:= 0;
- RunPat:= Pat;
- RunText:= Text;
- while RunText^ <> #0 do
- begin
- if (CharTable[RunPat^] = CharTable[RunText^]) then
- begin
- PosPtr := RunText;
- while RunPat^ <> #0 do begin
- if (CharTable[RunPat^] <> CharTable[RunText^]) then break;
- inc(RunPat); inc(RunText);
- end;
- if RunPat^ = #0 then
- begin
- Result:= PosPtr - Text +1;
- break;
- end;
- end else inc(RunText);
- RunPat:= Pat;
- end;
- end; {IPos }
-
- function IPosE(Pat, Text: PChar; StartPos, MaxPos: LongInt): Integer;
- var
- AChar: char;
-
- RunPat,
- RunText,
- PosPtr: PChar;
- begin
- Result:= 0;
- RunPat:= Pat;
-
- RunText := Text + MaxPos;
- AChar := RunText^;
- RunText^ := #0;
-
- RunText := Text + StartPos -1;
-
- while RunText^ <> #0 do
- begin
- if (CharTable[RunPat^] = CharTable[RunText^]) then
- begin
- PosPtr := RunText;
-
- while RunPat^ <> #0 do
- begin
- if (CharTable[RunPat^] <> CharTable[RunText^]) then
- break;
-
- inc(RunPat); inc(RunText);
- end;
-
- if (RunPat^ = #0) then
- begin
- Result:= PosPtr - Text +1;
- break;
- end;
-
- end
- else
- inc(RunText);
-
- RunPat := Pat;
- end;
-
- RunText := Text + MaxPos;
- RunText^ := AChar;
-
- end; {IPosE }
-
- function FastPos(Sign: Char; ToScan: PChar): integer;
- var
- Input: PChar;
- begin
- Result := 0;
- Input := ToScan;
- while (ToScan^ <> #0) do
- begin
- if ToScan^ = Sign then
- begin
- Result := ToScan - Input;
- break;
- end;
- inc(ToScan);
- end;
- end;
-
- {$IFDEF VER100}
- resourcestring
- {$ELSE}
- const
- {$ENDIF}
- msgErrBlanks = 'Expression has blanks';
- msgMissingBrackets = 'Missing brackets in expression (%s)';
- msgParseError = 'Error parsing expression:';
- msgNestings = 'Expression contains too many nestings';
- msgTooComplex = 'Expression is too complex';
- msgInternalError = 'TParser internal error';
-
- const
- TokenOperators = [ sum, diff, prod, divis, modulo, IntDiv,
- integerpower, realpower];
-
- type
- TermString = string;
-
- procedure ParseFunction( FunctionString: string;
- Variables: TStringList;
-
- FunctionOne,
- FunctionTwo: TStringList;
-
- UsePascalNumbers: boolean;
-
- var FirstOP: POperation;
-
- var Error: boolean);
-
-
- function CheckNumberBrackets(const s: string): integer; forward;
- { checks whether number of ( = number of ) }
-
- function CheckNumber(const s: string; var FloatNumber: ParserFloat): boolean; forward;
- { checks whether s is a number }
-
- function CheckVariable(const s: string; var VariableID: integer): boolean; forward;
- { checks whether s is a variable string }
-
- function CheckTerm(var s1: string): boolean; forward;
- { checks whether s is a valid term }
-
- function CheckBracket(const s: string; var s1: string): boolean; forward;
- { checks whether s =(...(s1)...) and s1 is a valid term }
-
-
-
- function CheckNegate(const s: string; var s1: string): boolean; forward;
- {checks whether s denotes the negative value of a valid operation}
-
-
-
- function CheckAdd(var s: string; var s1, s2: string): boolean; forward;
- {checks whether + is the primary operation in s}
-
- function CheckSubtract(const s: string; var s1, s2: string): boolean; forward;
- {checks whether - is the primary operation in s}
-
- function CheckMultiply(const s: string; var s1, s2: string): boolean; forward;
- {checks whether * is the primary operation in s}
-
- {$IFDEF UseIntegerOP}
- function CheckIntegerDiv(const s: string; var s1, s2: string): boolean; forward;
- {checks whether DIV is the primary TOperation in s}
-
- function CheckModulo(const s: string; var s1, s2: string): boolean; forward;
- {checks whether MOD is the primary TOperation in s}
- {$ENDIF UseIntegerOP}
-
- function CheckRealDivision(const s: string; var s1, s2: string): boolean; forward;
- {checks whether / is the primary operation in s}
-
-
-
- function CheckFuncTwoVar(var s: string; var s1, s2: string): boolean; forward;
- {checks whether s=f(s1,s2); s1,s2 being valid terms}
-
- function CheckFuncOneVar(var s: string; var s1: string): boolean; forward;
- {checks whether s denotes the evaluation of a function fsort(s1)}
-
-
- function CheckPower(const s: string; var s1, s2: string; var AToken: TToken): boolean; forward;
-
-
- function CheckNumberBrackets(const s: string): integer;
- {checks whether # of '(' equ. # of ')'}
- var
- counter: integer;
- begin
- Result := 0;
-
- counter := length(s);
- while counter <> 0 do
- begin
- case s[counter] of
- '(': inc(Result);
- ')': dec(Result);
- end;
- dec(counter);
- end;
- end;
-
-
- function CheckNumber(const s: string; var FloatNumber: ParserFloat):boolean;
- {checks whether s is a number}
- var
- code: integer;
- begin
- if s = 'PI' then
- begin
- FloatNumber := Pi;
- Result := true;
- end
- else
- if s = '-PI' then
- begin
- FloatNumber := -Pi;
- Result := true;
- end
- else
- begin
- if UsePascalNumbers then
- begin
- val(s, FloatNumber, code);
- Result := code = 0;
- end
- else
- Result := TryStrToFloat(s, FloatNumber);
- end;
- end;
-
-
- function CheckVariable(const s: string; var VariableID: integer): boolean;
- {checks whether s is a variable string}
- begin
- Result := Variables.Find(s, VariableID);
- end;
-
-
- function CheckTerm(var s1: string) :boolean;
- { checks whether s is a valid term }
- var
- s2, s3: TermString;
- FloatNumber: ParserFloat;
- fsort: TToken;
- VariableID: integer;
- begin
- Result := false;
-
- if length(s1) = 0 then
- exit;
-
- if CheckNumber(s1, FloatNumber) or
- CheckVariable(s1, VariableID) or
- CheckNegate(s1, s2) or
- CheckAdd(s1, s2, s3) or
- CheckSubtract(s1, s2, s3) or
- CheckMultiply(s1, s2, s3) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s1, s2, s3) or
- CheckModulo(s1, s2, s3) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s1, s2, s3) or
- CheckPower(s1, s2, s3, fsort) or
- CheckFuncTwoVar(s1, s2, s3) or
- CheckFuncOneVar(s1, s2)
- then
- Result := true
- else
- if CheckBracket(s1, s2) then
- begin
- s1 := s2;
- Result := true
- end;
-
- end;
-
- function CheckBracket(const s: string; var s1: string): boolean;
- {checks whether s =(...(s1)...) and s1 is a valid term}
- var
- SLen : integer;
- begin
- Result := false;
-
- SLen := Length(s);
- if (SLen > 0) and (s[SLen] = ')') and (s[1] = '(') then
- begin
- s1 := copy(s, 2, SLen-2);
- Result := CheckTerm(s1);
- end;
- end;
-
-
- function CheckNegate(const s: string; var s1: string) :boolean;
- {checks whether s denotes the negative value of a valid TOperation}
- var
- s2, s3: TermString;
- fsort: TToken;
- VariableID: integer;
- begin
- Result := false;
-
- if (length(s) <> 0) and (s[1] = '-') then
- begin
-
- s1 := copy(s, 2, length(s)-1);
- if CheckBracket(s1, s2) then
- begin
- s1 := s2;
- Result := true;
- end
- else
- Result :=
- CheckVariable(s1, VariableID) or
- CheckPower(s1, s2, s3, fsort) or
- CheckFuncOneVar(s1, s2) or
- CheckFuncTwoVar(s1, s2, s3);
-
- end;
- end;
-
-
- function CheckAdd(var s: string; var s1, s2: string): boolean;
- {checks whether '+' is the primary TOperation in s}
- var
- s3, s4: TermString;
- OldLen,
- i, j: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- VariableID: integer;
- begin
- Result := false;
-
- i := 0;
- j := length(s);
- repeat
-
- while i < j do
- begin
- inc(i);
- if s[i] = '+' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
-
- Result := false;
-
- s2 := copy(s, i+1, j-i);
- if CheckNumberBrackets(s2) = 0 then
- begin
- OldLen := HackSetLength(S, i-1);
- Result := CheckNumberBrackets(s) = 0;
- HackSetLength(S, OldLen);
-
- if Result then
- begin
- s1 := copy(s, 1, i-1);
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
-
- if not Result then
- Result := CheckNegate(s1, s3) or
- CheckSubtract(s1, s3, s4) or
- CheckMultiply(s1, s3, s4) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
- Result := CheckNumber(s2, FloatNumber) or CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckAdd(s2, s3, s4) or
- CheckSubtract(s2, s3, s4) or
- CheckMultiply(s2, s3, s4) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s2, s3, s4) or
- CheckModulo(s2, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s2, s3, s4) or
- CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
- end;
- end;
-
-
- end
- end
- end
- else
- break;
-
- until Result;
- end;
-
-
-
- function CheckSubtract(const s: string; var s1, s2: string): boolean;
- {checks whether '-' is the primary TOperation in s}
- var
- s3, s4: TermString;
- i, j: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- VariableID: integer;
- begin
- Result := false;
-
- i := 1; { bugfix -1-1 }
- j := length(s);
-
- repeat
-
- while i < j do { bugfix -1-1 }
- begin
- inc(i);
- if s[i] = '-' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+1, j-i);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
- if not Result then
- Result := CheckNegate(s1, s3) or
- CheckSubtract(s1, s3, s4) or
- CheckMultiply(s1, s3, s4) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
- Result := CheckNumber(s2, FloatNumber) or CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckMultiply(s2, s3, s4) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s2, s3, s4) or
- CheckModulo(s2, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s2, s3, s4) or
- CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
- end;
- end;
-
- end;
- end
- else
- break;
-
- until Result;
-
- end;
-
-
- function CheckMultiply(const s: string; var s1, s2: string): boolean;
- {checks whether '*' is the primary TOperation in s}
- var
- s3, s4: TermString;
- i, j: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- VariableID: integer;
- begin
- Result := false;
-
- i := 0;
- j := length(s);
-
- repeat
- while i < j do
- begin
- inc(i);
- if s[i] = '*' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+1, j-i);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
-
- if not Result then
- Result := CheckNegate(s1, s3) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
- Result := CheckNumber(s2, FloatNumber) or CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckMultiply(s2, s3, s4) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s2, s3, s4) or
- CheckModulo(s2, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s2, s3, s4) or
- CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
- end;
- end;
-
- end;
- end
- else
- break;
-
- until Result;
- end;
-
- {$IFDEF UseIntegerOP}
- function CheckIntegerDiv(const s: string; var s1, s2: string): boolean;
- {checks whether 'DIV' is the primary TOperation in s}
- var
- s3, s4: TermString;
- i, j: integer;
- VariableID: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- begin
- Result := false;
-
- i := 0;
-
- repeat
-
- {$IFDEF Win32}
- // j := IPos('DIV', PChar(copy(s, i+1, length(s)-i)));
-
- j := IPosE('DIV', PChar(s), i+1, length(s)-i);
- {$ELSE}
- j := pos('DIV', copy(s, i+1, length(s)-i));
- {$ENDIF Win32}
-
- if j > 0 then
- begin
-
- inc(i, j);
- if (i > 1) and (i < length(s)) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+3, length(s)-i-2);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
-
- if not Result then
- Result := CheckNegate(s1, s3) or
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
- if Result then
- begin
- Result := CheckNumber(s2,FloatNumber) or CheckVariable(s2,VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
- end;
- end;
-
-
- end;
- end;
- end;
-
- until Result or (j = 0) or (i >= length(s));
- end;
-
- function CheckModulo(const s: string; var s1, s2: string): boolean;
- {checks whether 'MOD' is the primary TOperation in s}
- var
- s3, s4: TermString;
- i, j: integer;
- VariableID: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- begin
- Result := false;
-
- i := 0;
-
- repeat
- {$IFDEF Win32}
- // j := IPos('MOD', PChar(copy(s, i+1, length(s)-i)));
-
- j := IPosE('MOD', PChar(s), i+1, length(s)-i);
- {$ELSE}
- j := pos('MOD', copy(s, i+1, length(s)-i));
- {$ENDIF Win32}
- if j > 0 then
- begin
-
- inc(i, j);
- if (i > 1) and (i < length(s)) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+3, length(s)-i-2);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
- if not Result then
- Result := CheckNegate(s1, s3) or
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
- Result := CheckNumber(s2, FloatNumber) or CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
-
- end
- end;
-
-
- end;
- end;
- end;
- until Result or (j = 0) or (i >= length(s));
- end;
- {$ENDIF UseIntegerOP}
-
-
- function CheckRealDivision(const s: string; var s1, s2: string): boolean;
- {checks whether '/' is the primary TOperation in s}
- var
- s3, s4: TermString;
- i, j: integer;
- VariableID: integer;
- FloatNumber: ParserFloat;
- fsort: TToken;
- begin
- Result := false;
-
- i := 0;
- j := length(s);
-
- repeat
-
- while i < j do
- begin
- inc(i);
- if s[i] = '/' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+1, j-i);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
-
- if not Result then
- Result := CheckNegate(s1, s3) or
- {$IFDEF UseIntegerOP}
- CheckIntegerDiv(s1, s3, s4) or
- CheckModulo(s1, s3, s4) or
- {$ENDIF UseIntegerOP}
- CheckRealDivision(s1, s3, s4) or
- CheckPower(s1, s3, s4, fsort) or
- CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
- Result := CheckNumber(s2, FloatNumber) or CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3
- else
- Result := CheckPower(s2, s3, s4, fsort) or
- CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
-
- end;
- end;
-
- end;
- end
- else
- break;
-
- until Result;
- end;
-
-
- function CheckFuncTwoVar(var s: string; var s1, s2: string): boolean;
- {checks whether s=f(s1,s2); s1,s2 being valid terms}
-
- function CheckComma(const s: string; var s1, s2: string): boolean;
- var
- i, j: integer;
- begin
- Result := false;
-
- i := 0;
- j := length(s);
- repeat
-
- while i < j do
- begin
- inc(i);
- if s[i] = ',' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
- s1 := copy(s, 1, i-1);
- if CheckTerm(s1) then
- begin
- s2 := copy(s, i+1, j-i);
- Result := CheckTerm(s2);
- end;
-
- end
- else
- break;
-
- until Result;
- end;
-
- var
- OldLen,
- SLen,
- counter : integer;
- begin
-
- Result := false;
-
- {$IFDEF Win32}
- SLen := FastPos('(', PChar(s));
- {$ELSE}
- SLen := Pos('(', s);
- dec(SLen);
- {$ENDIF Win32}
-
- if (SLen > 0) and (s[length(s)] = ')') then
- begin
-
- OldLen := HackSetLength(S, SLen);
- Result := FunctionTwo.Find(s, counter);
- HackSetLength(S, OldLen);
-
- { Result := FunctionTwo.Find(copy(s, 1, SLen), counter); }
- if Result then
- begin
- inc(SLen, 2);
- Result := CheckComma( copy(s, SLen, length(s)-SLen), s1, s2);
- end;
- end;
- end;
-
-
- function CheckFuncOneVar(var s: string; var s1: string): boolean;
- {checks whether s denotes the evaluation of a function fsort(s1)}
- var
- OldLen,
- counter: integer;
- SLen: integer;
- begin
- Result := false;
-
- { change}
- {$IFDEF Win32}
- SLen := FastPos('(', PChar(s));
- {$ELSE}
- SLen := Pos('(', s);
- dec(SLen);
- {$ENDIF Win32}
-
- if (SLen > 0) then
- begin
- OldLen := HackSetLength(S, SLen);
- Result := FunctionOne.Find(s, counter);
- HackSetLength(S, OldLen);
-
- { Result := FunctionOne.Find(copy(s, 1, SLen), counter); }
- if Result then
- begin
- Result := CheckBracket(copy(s, SLen+1, length(s)-SLen), s1);
- end;
- end;
- end;
-
- function CheckPower(const s: string; var s1, s2: string; var AToken: TToken): boolean;
- var
- s3, s4: TermString;
- i, j: integer;
- FloatNumber: ParserFloat;
- VariableID: integer;
- begin
- Result := false;
-
- i := 0;
- j := length(s);
- repeat
-
- while i < j do
- begin
- inc(i);
- if s[i] = '^' then
- break;
- end;
-
- if (i > 1) and (i < j) then
- begin
- s1 := copy(s, 1, i-1);
- s2 := copy(s, i+1, j-i);
-
- Result := (CheckNumberBrackets(s2)=0) and (CheckNumberBrackets(s1)=0);
-
- if Result then
- begin
- Result := CheckNumber(s1, FloatNumber) or CheckVariable(s1, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s1, s3);
- if Result then
- s1 := s3;
- end;
-
- if not Result then
- Result := CheckFuncOneVar(s1, s3) or
- CheckFuncTwoVar(s1, s3, s4);
-
- if Result then
- begin
-
- if CheckNumber(s2, FloatNumber) then
- begin
- i := trunc(FloatNumber);
-
- if (i <> FloatNumber) then
- begin
- { this is a real number }
- AToken := realpower;
- end
- else
- begin
- case i of
- 2: AToken := square;
- 3: AToken := third;
- 4: AToken := fourth;
- else
- AToken := integerpower;
- end;
- end;
- end
- else
- begin
- Result := CheckVariable(s2, VariableID);
-
- if not Result then
- begin
- Result := CheckBracket(s2, s3);
- if Result then
- s2 := s3;
- end;
-
- if not Result then
- begin
- Result := CheckFuncOneVar(s2, s3) or
- CheckFuncTwoVar(s2, s3, s4);
- end;
-
- if Result then
- AToken := realPower;
- end;
- end;
-
- end;
- end
- else
- break;
-
- until Result;
- end;
-
- function CreateOperation(const Term: TToken; const Proc: Pointer): POperation;
- begin
- new(Result);
- with Result^ do
- begin
- Arg1 := nil;
- Arg2 := nil;
- Dest := nil;
-
- NextOperation := nil;
-
- Token := Term;
-
- MathProc := TMathProcedure(Proc);
- end;
- end;
-
- const
- BlankString = ' ';
-
- type
- PTermRecord = ^TermRecord;
- TermRecord = record
- { this usage of string is a bit inefficient,
- as in 16bit always 256 bytes are consumed.
- But since we
- a) are allocating memory dynamically and
- b) this will be released immediately when
- finished with parsing
- this seems to be OK
-
- One COULD create a "TermClass" where this is handled }
- StartString: string;
- LeftString, RightString: string;
-
- Token: TToken;
-
- Position: array[1..3] of integer;
-
- Next1,
- Next2,
- Previous: PTermRecord;
- end;
-
-
- const
- { side effect: for each bracketing level added
- SizeOf(integer) bytes additional stack usage
- maxLevelWidth*SizeOf(Pointer) additional global memory used }
- maxBracketLevels = 20;
-
- { side effect: for each additional (complexity) level width
- maxBracketLevels*SizeOf(Pointer) additional global memory used }
- maxLevelWidth = 50;
- type
- LevelArray = array[0..maxBracketLevels] of integer;
-
- OperationPointerArray = array[0..maxBracketLevels, 1..maxLevelWidth] of POperation;
- POperationPointerArray = ^OperationPointerArray;
-
- var
- Matrix: POperationPointerArray;
-
- { bracket positions }
- CurrentBracket,
- i,
- CurBracketLevels: integer;
-
- BracketLevel: LevelArray;
-
- LastOP: POperation;
- FloatNumber: ParserFloat;
- VariableID: integer;
-
-
- ANewTerm, { need this particlar pointer to guarantee a good, flawless memory cleanup in except }
-
- FirstTerm,
- Next1Term,
- Next2Term,
- LastTerm: PTermRecord;
-
- counter1,
- counter2: integer;
- begin
- { initialize local variables for safe checking in try..finally..end}
-
- { FirstTerm := nil; } { not necessary since not freed in finally }
- LastTerm := nil;
- ANewTerm := nil;
- Next1Term := nil;
- Next2Term := nil;
-
- Error := false;
-
- FillChar(BracketLevel, SizeOf(BracketLevel), 0); { initialize bracket array }
- BracketLevel[0] := 1;
- CurBracketLevels := 0;
-
- new(Matrix);
-
- try { this block protects the whole of ALL assignments...}
- FillChar(Matrix^, SizeOf(Matrix^), 0);
-
- new(ANewTerm);
- with ANewTerm^ do
- begin
-
- StartString := UpperCase(FunctionString);
-
- { remove leading and trailing spaces }
- counter1 := 1;
- counter2 := length(StartString);
- while counter1 <= counter2 do
- if StartString[counter1] <> ' ' then
- break
- else
- inc(counter1);
-
- counter2 := length(StartString);
- while counter2 > counter1 do
- if StartString[counter2] <> ' ' then
- break
- else
- dec(counter2);
-
- StartString := Copy(StartString, counter1, counter2 - counter1 + 1);
-
- { change }
- {$IFDEF Win32}
- if FastPos(' ', PChar(StartString)) <> 0 then
- {$ELSE}
- if Pos(' ', StartString) > 0 then
- {$ENDIF Win32}
- raise EExpressionHasBlanks.Create(msgErrBlanks);
- {
- Old code:
-
- StartString := RemoveBlanks(UpperCase(FunctionString));
-
- ...do not use! Using it would create the following situation:
-
- Passed string: "e xp(12)"
- Modified string: "exp(12)"
-
- This MAY or may not be the desired meaning - there may well exist
- a variable "e" and a function "xp" and just the operator would be missing.
-
- Conclusion: the above line has the potential of changing the meaning
- of an expression.
- }
-
- i := CheckNumberBrackets(StartString);
- if i > 0 then
- raise EMissMatchingBracket.CreateFmt(msgMissingBrackets, ['")"', i])
- else
- if i < 0 then
- raise EMissMatchingBracket.CreateFmt(msgMissingBrackets, ['"("', i]);
-
- { remove enclosing brackets, e.g. ((pi)) }
- while CheckBracket(StartString, FunctionString) do
- StartString := FunctionString;
-
- LeftString := BlankString;
- RightString := BlankString;
-
- Token := variab;
-
- Next1 := nil;
- Next2 := nil;
- Previous := nil;
- end;
-
- Matrix[0,1] := CreateOperation(variab, nil);
-
- LastTerm := ANewTerm;
- FirstTerm := ANewTerm;
- ANewTerm := nil;
-
- with LastTerm^ do
- begin
- Position[1] := 0;
- Position[2] := 1;
- Position[3] := 1;
- end;
-
- repeat
-
- repeat
-
- with LastTerm^ do
- begin
-
- CurrentBracket := Position[1];
- i := Position[2];
-
- if Next1 = nil then
- begin
- if CheckNumber(StartString, FloatNumber) then
- begin
- Token := constant;
- if Position[3] = 1 then
- begin
- new(Matrix[CurrentBracket, i]^.Arg1);
- Matrix[CurrentBracket, i]^.Arg1^ := FloatNumber;
- end
- else
- begin
- new(Matrix[CurrentBracket, i]^.Arg2);
- Matrix[CurrentBracket, i]^.Arg2^ := FloatNumber;
- end;
- end
- else
- begin
- if CheckVariable(StartString, VariableID) then
- begin
- Token := variab;
-
- if Position[3] = 1 then
- Matrix[CurrentBracket, i]^.Arg1 := PParserFloat(Variables.Objects[VariableID])
- else
- Matrix[CurrentBracket, i]^.Arg2 := PParserFloat(Variables.Objects[VariableID])
- end
- else
- begin
- if CheckNegate(StartString, LeftString) then
- Token := minus
- else
- begin
- if CheckAdd(StartString, LeftString, RightString) then
- Token := sum
- else
- begin
- if CheckSubtract(StartString, LeftString, RightString) then
- Token := diff
- else
- begin
- if CheckMultiply(StartString, LeftString, RightString) then
- Token := prod
- else
- begin
- {$IFDEF UseIntegerOP}
- if CheckIntegerDiv(StartString, LeftString, RightString) then
- Token := IntDiv
- else
- begin
- if CheckModulo(StartString, LeftString, RightString) then
- Token := modulo
- else
- {$ELSE}
- begin
- {$ENDIF UseIntegerOP}
- begin
- if CheckRealDivision(StartString, LeftString, RightString) then
- Token := divis
- else
- begin
- if not CheckPower(StartString, LeftString, RightString, Token) then
- begin
- if CheckFuncOneVar(StartString, LeftString) then
- Token := FuncOneVar
- else
- begin
- if CheckFuncTwoVar(StartString, LeftString, RightString) then
- Token := FuncTwoVar
- else
- begin
- Error := true; {with an exception raised this is meaningless...}
- if (LeftString = BlankString) and (RightString = BlankString) then
- raise ESyntaxError.CreateFmt(
- msgParseError+#13'%s', [StartString]
- )
- else
- raise ESyntaxError.CreateFmt(
- msgParseError+#13'%s'#13'%s', [Leftstring, RightString]
- )
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end; { with LastTerm^ }
-
-
- if LastTerm^.Token in ( [minus, square, third, fourth, FuncOneVar, FuncTwoVar] + TokenOperators) then
- begin
- if LastTerm^.Next1 = nil then
- begin
- try
- Next1Term := nil;
- new(Next1Term);
-
- inc(CurrentBracket);
- if CurrentBracket > maxBracketLevels then
- begin
- Error := true;
- raise ETooManyNestings.Create(msgNestings);
- end;
-
- i := BracketLevel[CurrentBracket] + 1;
- if i > maxLevelWidth then
- begin
- Error := true;
- raise EExpressionTooComplex.Create(msgTooComplex);
- end;
-
- if CurBracketLevels < CurrentBracket then
- CurBracketLevels := CurrentBracket;
-
- with Next1Term^ do
- begin
- StartString := LastTerm^.LeftString;
- LeftString := BlankString;
- RightString := BlankString;
-
- Position[1] := CurrentBracket;
- Position[2] := i;
- Position[3] := 1;
-
- Token := variab;
-
- Previous := LastTerm;
- Next1 := nil;
- Next2 := nil;
- end;
-
- with LastTerm^ do
- begin
- case Token of
- FuncOneVar:
- with FunctionOne do
- begin
- {$IFDEF Win32}
- SetLength(StartString, FastPos('(', PChar(StartString)));
- {$ELSE}
- StartString[0] := chr(Pos('(', StartString)-1);
- {$ENDIF Win32}
- Find(StartString, counter1);
-
- Matrix[CurrentBracket, i] := CreateOperation(
- Token, Objects[counter1] );
-
- end;
-
-
- FuncTwoVar:
- with FunctionTwo do
- begin
- {$IFDEF Win32}
- SetLength(StartString, FastPos('(', PChar(StartString)));
- {$ELSE}
- StartString[0] := chr(Pos('(', StartString)-1);
- {$ENDIF Win32}
- Find(StartString, counter1);
-
- Matrix[CurrentBracket, i] := CreateOperation(
- Token, Objects[counter1] );
- end;
- else
- Matrix[CurrentBracket, i] := CreateOperation(Token, nil);
- end;
-
- new(Matrix[CurrentBracket, i]^.Dest);
- Matrix[CurrentBracket, i]^.Dest^ := 0;
-
- if Position[3] = 1 then
- Matrix[Position[1], Position[2]]^.Arg1 :=
- Matrix[CurrentBracket, i]^.Dest
- else
- Matrix[Position[1], Position[2]]^.Arg2 :=
- Matrix[CurrentBracket, i]^.Dest;
-
- Next1 := Next1Term;
- Next1Term := nil;
- end;
-
- if LastTerm^.Token in [minus, square, third, fourth, FuncOneVar] then
- inc(BracketLevel[CurrentBracket]);
-
- except
- if assigned(Next1Term) then
- begin
- dispose(Next1Term);
- Next1Term := nil;
- end;
- raise;
- end;
-
- end
-
- else
- begin
- if LastTerm^.Token in (TokenOperators + [FuncTwoVar]) then
- begin
- try
- Next2Term := nil;
- new(Next2Term);
-
- inc(CurrentBracket);
- if CurrentBracket > maxBracketLevels then
- begin
- Error := true;
- raise ETooManyNestings.Create(msgNestings);
- end;
-
- i := BracketLevel[CurrentBracket] + 1;
- if i > maxLevelWidth then
- begin
- Error := true;
- raise EExpressionTooComplex.Create(msgTooComplex);
- end;
-
- if CurBracketLevels < CurrentBracket then
- CurBracketLevels := CurrentBracket;
-
- with Next2Term^ do
- begin
- StartString := LastTerm^.RightString;
-
- LeftString := BlankString;
- RightString := BlankString;
-
- Token := variab;
-
- Position[1] := CurrentBracket;
- Position[2] := i;
- Position[3] := 2;
-
- Previous := LastTerm;
- Next1 := nil;
- Next2 := nil;
- end;
-
- LastTerm^.Next2 := Next2Term;
- Next2Term := nil;
- inc(BracketLevel[CurrentBracket]);
-
- except
- if assigned(Next2Term) then
- begin
- dispose(Next2Term);
- Next2Term := nil;
- end;
-
- raise;
- end;
- end
- else
- raise EParserInternalError.Create(msgInternalError);
- end;
- end;
-
-
- with LastTerm^ do
- if Next1 = nil then
- begin
- { we are done with THIS loop }
- break;
- end
- else
- if Next2 = nil then
- LastTerm := Next1
- else
- LastTerm := Next2;
-
- until false; { endless loop, break'ed 7 lines above }
-
- if LastTerm = FirstTerm then
- begin
- dispose(LastTerm);
- FirstTerm := nil;
- break; { OK - that is it, we did not find any more terms}
- end;
-
- repeat
- with LastTerm^ do { cannot use "with LastTerm^" OUTSIDE loop }
- begin
- if Next1 <> nil then
- begin
- dispose(Next1);
- Next1 := nil;
- end;
-
- if Next2 <> nil then
- begin
- dispose(Next2);
- Next2 := nil;
- end;
-
- LastTerm := Previous;
- end;
- until ((LastTerm^.Token in (TokenOperators + [FuncTwoVar])) and (LastTerm^.Next2 = nil)) or
- (LastTerm = FirstTerm);
-
- with FirstTerm^ do
- if (LastTerm = FirstTerm) and
- ( (Token in [minus, square, third, fourth, FuncOneVar]) or
- ((Token in (TokenOperators + [FuncTwoVar])) and Assigned(Next2))
- ) then
- begin
- break;
- end;
-
-
- until false;
-
-
- { after having built the expression matrix, translate it into a tree/list }
-
- with FirstTerm^ do
- if FirstTerm <> nil then
- begin
- if Next1 <> nil then
- begin
- dispose(Next1);
- Next1 := nil;
- end;
-
- if Next2 <> nil then
- begin
- dispose(Next2);
- Next2 := nil;
- end;
-
- dispose(FirstTerm);
- end;
-
- BracketLevel[0] := 1;
-
- if CurBracketLevels = 0 then
- begin
- FirstOP := Matrix[0,1];
- Matrix[0,1] := nil;
- FirstOP^.Dest := FirstOP^.Arg1;
- end
- else
- begin
-
- FirstOP := Matrix[CurBracketLevels, 1];
- LastOP := FirstOP;
-
- for counter2 := 2 to BracketLevel[CurBracketLevels] do
- begin
- LastOP^.NextOperation := Matrix[CurBracketLevels, counter2];
- LastOP := LastOP^.NextOperation;
- end;
-
-
- for counter1 := CurBracketLevels-1 downto 1 do
- for counter2 := 1 to BracketLevel[counter1] do
- begin
- LastOP^.NextOperation := Matrix[counter1, counter2];
- LastOP := LastOP^.NextOperation;
- end;
-
-
- with Matrix[0,1]^ do
- begin
- Arg1 := nil;
- Arg2 := nil;
- Dest := nil;
- end;
-
- dispose(Matrix[0,1]);
- end;
-
- dispose(Matrix);
-
- except
- if Assigned(Matrix) then
- begin
- if Matrix[0,1] <> nil then
- dispose(Matrix[0,1]);
-
- for counter1 := CurBracketLevels downto 1 do
- for counter2 := 1 to BracketLevel[counter1] do
- if Matrix[counter1, counter2] <> nil then
-
- dispose(Matrix[counter1, counter2]);
-
- dispose(Matrix);
- end;
-
- if Assigned(Next1Term) then
- dispose(Next1Term);
-
- if Assigned(Next2Term) then
- dispose(Next2Term);
-
- { do NOT kill this one at it is possibly the same as LastTerm (see below)!
- if Assigned(FirstTerm) then
- dispose(FirstTerm);
-
- instead, DO kill ANewTerm, which will only be <> nil if it has NOT passed
- its value to some other pointer already so it can safely be freed
- }
- if Assigned(ANewTerm) then
- dispose(ANewTerm);
-
- if Assigned(LastTerm) and (LastTerm <> Next2Term) and (LastTerm <> Next1Term) then
- dispose(LastTerm);
-
- FirstOP := nil;
-
- raise; { re-raise exception }
- end;
- end;
-
- initialization
- MakeCharTable;
- end.
-
-